package com.qyb.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.qyb.pdf.util.PathUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
/*import org.jpedal.PdfDecoder;
import org.jpedal.exception.PdfException;
import org.jpedal.fonts.FontMappings;*/
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * *************************************************************************************************
 * <p/>
 * 实现功能：
 * <p>
 * ------------------------------------------------------------------------------------------------
 * 版本          变更时间             变更人                     变更原因
 * ------------------------------------------------------------------------------------------------
 * 1.0.00      2017/7/27 13:40      秦有宝                     新建
 * <p/>
 * *************************************************************************************************
 */

/*
iText是著名的开放源码的站点sourceforge一个项目，是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档，而且可以将XML、Html文件转化为PDF文件。
iText目前有两套版本iText5和iText7。iText5应该是网上用的比较多的一个版本。iText5因为是很多开发者参与贡献代码，因此在一些规范和设计上存在不合理的地方。
iText7是后来官方针对iText5的重构，两个版本差别还是挺大的。不过在实际使用中，一般用到的都比较简单，所以不用特别拘泥于使用哪个版本。
比如我们在http://mvnrepository.com/中搜索iText，出来的都是iText5的依赖。
 */

public class JavaToPdf {

    private static final String DEST1 = "target/HelloWorld.pdf";

    /*
      最简单的例子:
     */
    public static void demo1() throws FileNotFoundException, DocumentException {
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST1));
        document.open();
        document.add(new Paragraph("hello world"));
        document.close();
        writer.close();
    }


    private static final String DEST2 = "target/HelloWorld_CN.pdf";
    private static final String FONT = "simhei.ttf";
    /*
      使用中文字体：iText默认是不支持中文的，因此需要添加对应的中文字体,比如黑体simhei.ttf
      参考: http://developers.itextpdf.com/examples/font-examples/using-fonts#1227-tengwarquenya1.java
     */
    public static void demo2() throws FileNotFoundException, DocumentException {
        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST2));
        document.open();
        Font f1 = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        document.add(new Paragraph("hello world：你好，世界", f1));
        document.close();
        writer.close();
    }

    /**
     * 在一些比较复杂的pdf布局中，我们可以通过html去生成pdf
     * 参考：http://developers.itextpdf.com/examples/xml-worker-itext5/xml-worker-examples
     * 需要注意:
         1.html中必须使用标准的语法，标签一定需要闭合
         2.html中如果有中文，需要在样式中添加对应字体的样式
     */
    private static final String DEST3 = "target/HelloWorld_CN_HTML.pdf";
    private static final String HTML = PathUtil.getCurrentPath()+"/template.html";

//    private static final String DEST3 = "D:/my.pdf";
//    private static final String HTML = "D:/testword.html";

    public static void demo3() throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST3));
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new FileInputStream(HTML), null, Charset.forName("UTF-8"), fontImp);
        // step 5
        document.close();
    }

    /**
     * 在实际使用中，html内容都是动态渲染的，因此我们需要加入模板引擎支持，可以使用FreeMarker/Velocity，这里使用FreeMarker举例
     * 目前为止，我们已经实现了iText通过Html模板生成Pdf的功能，但是实际应用中，
     * 我们发现iText并不能对高级的CSS样式进行解析，比如CSS中的position属性等，因此我们要引入新的组件
     */
    private static final String DEST4 = "target/HelloWorld_CN_HTML_FREEMARKER.pdf";
    private static final String HTML1 = "template_freemarker.html";

    private static Configuration freemarkerCfg = null;

    static {
        freemarkerCfg =new Configuration();
        //freemarker的模板目录
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(PathUtil.getCurrentPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void demo4() throws IOException, DocumentException {
        Map<String,Object> data = new HashMap();
        data.put("name","世界");
        String content = freeMarkerRender(data,HTML1);
        createPdf(content,DEST4);
    }

    private static void createPdf(String content,String dest) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
        // step 5
        document.close();

    }

    /**
     * freemarker渲染html
     */
    private static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            template.setEncoding("UTF-8");
            // 合并数据模型与模板
            template.process(data, out); //将合并后的数据和模板写入到流中，这里使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    /**
     * Flying Saucer is a pure-Java library for rendering arbitrary well-formed XML (or XHTML) using CSS 2.1 for layout and formatting,
     * output to Swing panels, PDF, and images.
     * Flying Saucer是基于iText的，支持对CSS高级特性的解析。
     */
    private static final String DEST5 = "target/HelloWorld_CN_HTML_FREEMARKER_FS.pdf";
    private static final String HTML2 = "template_freemarker_fs.html";
    private static final String LOGO_PATH = "file:/"+PathUtil.getCurrentPath()+"/";

    public static void demo5() throws IOException, DocumentException, com.lowagie.text.DocumentException {
        Map<String,Object> data = new HashMap();
        data.put("name","世界");
        String content = freeMarkerRender(data,HTML2);
        createPdf_fs(content,DEST5);
    }


    private static void createPdf_fs(String content,String dest) throws IOException, DocumentException, com.lowagie.text.DocumentException {
        ITextRenderer render = new ITextRenderer();
        ITextFontResolver fontResolver = render.getFontResolver();
        fontResolver.addFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        // 解析html生成pdf
        render.setDocumentFromString(content);
        //解决图片相对路径的问题
        render.getSharedContext().setBaseURL(LOGO_PATH);
        render.layout();
        render.createPDF(new FileOutputStream(dest));
    }

    /**
     * 在某些场景中，我们可能只需要返回图片格式的电子凭证，我们可以使用Jpedal组件，把pdf转成图片
     * Jpedal支持将指定页Pdf生成图片，pdfDecoder.scaling设置图片的分辨率(不同分辨率下文件大小不同) ，
     * 支持多种图片格式，具体更多可自行研究
     */
    private static final String DEST6 = "target/HelloWorld_CN_HTML_FREEMARKER_FS_IMG.png";
    private static final String IMG_EXT = "png";

    public static void demo6() throws IOException, DocumentException, com.lowagie.text.DocumentException {
        Map<String,Object> data = new HashMap();
        data.put("name","世界");

        String content = freeMarkerRender(data,HTML2);
        ByteArrayOutputStream pdfStream = createPdf(content);
//        ByteArrayOutputStream imgSteam = pdfToImg(pdfStream.toByteArray(),2,1,IMG_EXT);

        FileOutputStream fileStream = new FileOutputStream(new File(DEST6));
//        fileStream.write(imgSteam.toByteArray());
        fileStream.close();

    }

    /**
     * 根据模板生成pdf文件流
     */
    private static ByteArrayOutputStream createPdf(String content) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        ITextRenderer render = new ITextRenderer();
        ITextFontResolver fontResolver = render.getFontResolver();
        try {
            fontResolver.addFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        } catch (com.lowagie.text.DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 解析html生成pdf
        render.setDocumentFromString(content);
        //解决图片相对路径的问题
        render.getSharedContext().setBaseURL(LOGO_PATH);
        render.layout();
        try {
            render.createPDF(outStream);
            return outStream;
        } catch (com.lowagie.text.DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                outStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根据pdf二进制文件 生成图片文件
     *
     * @param bytes   pdf二进制
     * @param scaling 清晰度
     * @param pageNum 页数
     */
   /* private static ByteArrayOutputStream pdfToImg(byte[] bytes, float scaling, int pageNum,String formatName) {
        //推荐的方法打开PdfDecoder
        PdfDecoder pdfDecoder = new PdfDecoder(true);
        FontMappings.setFontReplacements();
        //修改图片的清晰度
        pdfDecoder.scaling = scaling;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            //打开pdf文件，生成PdfDecoder对象
            pdfDecoder.openPdfArray(bytes); //bytes is byte[] array with PDF
            //获取第pageNum页的pdf
            BufferedImage img = pdfDecoder.getPageAsImage(pageNum);

            ImageIO.write(img, formatName, out);
        } catch (PdfException e) {
            e.printStackTrace();
        } catch (IOException e){
            e.printStackTrace();
        }
        return out;
    }*/


}
